package com.link.base.tencent.secret.util;

import com.link.base.tencent.youtu.model.PublicAppInfo;
import com.link.core.basic.service.ServiceException;
import com.link.core.util.RedisUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.redisclient.LinkRedisClient;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Random;

/**
 * 密钥生成工具类
 *
 * @author ouyangzhenqiang
 * @date 2018/12/29
 */
public class SecretUtil {
    /**
     * 项目信息RedisKey
     */
    private static final String YOUTU_REDIS_KEY = "TENCENT_YOUTU_APP_INFO_";
    /**
     * 密钥默认有效期是1天
     */
    private static final long SECRET_EXPIRE_TIME = 86400;

    /**
     * 获取Redis中存储的密钥，如果已经过期，则重新获取
     *
     * @author ouyangzhenqiang
     * @date 2018/12/29
     * @param corpId
     */
    public static PublicAppInfo getExistSecret(String corpId) throws Exception {
        if (StringUtils.isBlank(corpId)) {
            throw new ServiceException("SECRET-001");
        }
        LinkRedisClient j = null;
        PublicAppInfo publicAppInfo = new PublicAppInfo();
        try {
            j = RedisUtil.getJedis();
            String corpYoutuRedisKey = YOUTU_REDIS_KEY + corpId;
            // 生成的接口密钥
            String redisSecret = j.hget(corpYoutuRedisKey, "YOUTU_APP_SECRET");
            // 密钥有效时间/秒
            String redisSecretExpire = j.hget(corpYoutuRedisKey, "YOUTU_APP_SECRET_EXPIRE");

            if (StringUtils.isBlank(redisSecret)) {
                // 密钥为空，直接生成
                redisSecret = getSecret(j, corpYoutuRedisKey);
                j.hset(corpYoutuRedisKey, "YOUTU_APP_SECRET", redisSecret);
                j.hset(corpYoutuRedisKey, "YOUTU_APP_SECRET_EXPIRE", String.valueOf(System.currentTimeMillis()));
            } else {
                // 密钥已存在，进行有效期校验
                Long redisSecretExpireLong = Long.parseLong(redisSecretExpire);
                Long currentTime = System.currentTimeMillis();
                int num = 1000;
                if (((currentTime - redisSecretExpireLong)) >= num * SECRET_EXPIRE_TIME) {
                    // 已过期，重新生成
                    redisSecret = getSecret(j, corpYoutuRedisKey);
                    j.hset(corpYoutuRedisKey, "YOUTU_APP_SECRET", redisSecret);
                    j.hset(corpYoutuRedisKey, "YOUTU_APP_SECRET_EXPIRE", String.valueOf(System.currentTimeMillis()));
                }
            }
            publicAppInfo.setAppId(j.hget(corpYoutuRedisKey, "YOUTU_APPID"));
            publicAppInfo.setSecret(redisSecret);
            publicAppInfo.setBucket(j.hget(corpYoutuRedisKey, "YOUTU_APP_BUCKET_NAME"));
        } finally {
            RedisUtil.returnResource(j);
        }
        return publicAppInfo;
    }

    /**
     * 生成Authorization签名字段
     *
     * @author ouyangzhenqiang
     * @date 2018/12/29
     * @param j
     * @param corpYoutuRedisKey
     * @return
     * @throws Exception
     */
    public static String getSecret(LinkRedisClient j, String corpYoutuRedisKey) throws Exception {
        // 腾讯云API_项目appId
        String appId = j.hget(corpYoutuRedisKey, "YOUTU_APPID");
        // 腾讯云API_项目秘钥ID
        String secretId = j.hget(corpYoutuRedisKey, "YOUTU_APP_SECRET_ID");
        // 腾讯云API_项目秘钥Key
        String secretKey = j.hget(corpYoutuRedisKey, "YOUTU_APP_SECRET_KEY");
        // 腾讯云API_图片空间bucket
        String bucketName = j.hget(corpYoutuRedisKey, "YOUTU_APP_BUCKET_NAME");
        if (StringUtils.isBlank(appId) || StringUtils.isBlank(secretId) || StringUtils.isBlank(secretKey) || StringUtils.isBlank(bucketName)) {
            throw new ServiceException("SECRET-002");
        }
        long appIdLong = Long.parseLong(appId);
        long now = System.currentTimeMillis() / 1000;
        int rdm = new Random().nextInt();
        String plainText = String.format("a=%d&b=%s&k=%s&t=%d&e=%d&r=%d", appIdLong, bucketName,
            secretId, now, now + SECRET_EXPIRE_TIME, rdm);
        byte[] hmacDigest = HmacSha1(plainText, secretKey);
        byte[] signContent = new byte[hmacDigest.length + plainText.getBytes().length];
        System.arraycopy(hmacDigest, 0, signContent, 0, hmacDigest.length);
        System.arraycopy(plainText.getBytes(), 0, signContent, hmacDigest.length,
            plainText.getBytes().length);
        return Base64Encode(signContent);
    }

    /**
     * 生成base64编码
     *
     * @author ouyangzhenqiang
     * @date 2018/12/29
     * @param binaryData
     */
    public static String Base64Encode(byte[] binaryData) {
        return Base64.getEncoder().encodeToString(binaryData);
    }

    /**
     * 生成hmacsha1签名
     *
     * @author ouyangzhenqiang
     * @date 2018/12/29
     * @param binaryData
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] HmacSha1(byte[] binaryData, String key) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA1");
        SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
        mac.init(secretKey);
        byte[] HmacSha1Digest = mac.doFinal(binaryData);
        return HmacSha1Digest;
    }

    /**
     * 生成hmacsha1签名
     *
     * @author ouyangzhenqiang
     * @date 2018/12/29
     * @param plainText
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] HmacSha1(String plainText, String key) throws Exception {
        return HmacSha1(plainText.getBytes(), key);
    }
}
